﻿using System;
using Lidgren.Network;
using System.Net;
using EclipseLib.Shared;
using System.Collections.Generic;

namespace Server
{
    public class ServerSocket
    {
        // Data Members
        NetServer Server;
        List<NetConnection> clients;

        // Member Properties
        public List<NetConnection> Clients
        {
            get { return clients; }
            protected set { clients = value; }
        }

        // Events & Delegates
        public delegate void ReceiveData(int Index, NetIncomingMessage Msg);
        public event ReceiveData OnReceiveData;

        // Constructor
        public ServerSocket()
        {
            NetPeerConfiguration Config = new NetPeerConfiguration(Constants.AppIdentifier);
            Config.Port = Constants.Port;
            Config.AcceptIncomingConnections = true;
            Config.MaximumConnections = Constants.MaxConnections;
            Config.ConnectionTimeout = 5f;
            Config.EnableMessageType(NetIncomingMessageType.DiscoveryRequest);

            Server = new NetServer(Config);
            Server.Start();
            Server.Socket.Blocking = false;

            Clients = new List<NetConnection>(Constants.MaxConnections);
            for (int i = 0; i < Constants.MaxConnections; ++i)
                Clients.Add(null);
        }
        public void SendData(int Index, NetOutgoingMessage Packet)
        {
            Server.SendMessage(Packet, Clients[Index], NetDeliveryMethod.ReliableUnordered);
        }
        public void SendDataToAll(NetOutgoingMessage Packet)
        {
            for (int i = 0; i < Constants.MaxConnections; ++i)
                if (Clients[i] != null)
                    SendData(i, Packet);
        }
        public void SendDataToAllBut(int Index, NetOutgoingMessage Packet)
        {
            for (int i = 0; i < Constants.MaxConnections; ++i)
                if(i != Index)
                    if (Clients[i] != null)
                        SendData(i, Packet);
        }
        public void Listen()
        {
            NetIncomingMessage Msg;

            while ((Msg = Server.ReadMessage()) != null)
            {
                int Index = Clients.IndexOf(Msg.SenderConnection);

                switch (Msg.MessageType)
                {
                    case NetIncomingMessageType.DiscoveryRequest:
                        Server.SendDiscoveryResponse(null, Msg.SenderEndpoint);
                        break;

                    case NetIncomingMessageType.StatusChanged:
                        {
                            NetConnectionStatus Status = (NetConnectionStatus)Msg.ReadByte();

                            switch (Status)
                            {
                                case NetConnectionStatus.Connected:
                                    {
                                        Clients[Clients.IndexOf(null, 0)] = Msg.SenderConnection;
                                        Index = Clients.IndexOf(Msg.SenderConnection);
                                        Network.LogMessage("Client connected: " + Clients[Index].RemoteEndpoint.Address.ToString());

                                        if (OnReceiveData != null)
                                            OnReceiveData(Index, Msg);
                                    }
                                    break;

                                case NetConnectionStatus.Disconnected:
                                    {
                                        Network.LogMessage("Client disconnected: " + Clients[Index].RemoteEndpoint.Address.ToString());
                                        // TODO: Clear Character Data

                                        Clients[Index] = null;
                                        if (OnReceiveData != null)
                                            OnReceiveData(Index, Msg);
                                    }
                                    break;
                            }
                        }
                        break;

                    default:
                        if (OnReceiveData != null)
                            OnReceiveData(Index, Msg);
                        break;
                }
            }
        }
        public NetOutgoingMessage CreateMessage()
        {
            return Server.CreateMessage();
        }
        public NetOutgoingMessage CreateMessage(int Capacity)
        {
            return Server.CreateMessage(Capacity);
        }
        public NetOutgoingMessage CreateMessage(string Content)
        {
            return Server.CreateMessage(Content);
        }
        public void Close()
        {
            Server.Shutdown("Goodbye!");
        }
    }
}